#ifndef __PROTOCOL__
#define __PROTOCOL__

#include <inttypes.h>
#include <stdbool.h>
#include <time.h>


#pragma pack(push, 1)

#define PROTOCOL_HEADER_MAGIC 0x1024

struct ProtocolHeader
{
	uint16_t magic, op, opsn;		// opsn: OP serial number
};

struct ChunkID
{
	union
	{
		struct
		{
			uint32_t volumeid, index;
		};
		uint64_t bits;
	};
};

struct Data
{
	uint32_t length;
	char buf[0];
};

#define CHUNK_CREATE					0
#define CHUNK_LIST						1
#define CHUNK_READ						2
#define CHUNK_WRITE						3
#define CHUNK_WRITE_REPLICATE			4
#define CHUNK_CREATE_WRITE_REPLICATE	5
#define CHUNK_GET_VERSION				6
#define CHUNK_FLUSH						7
#define CHUNK_DELETE					8
#define CHUNK_CHECKSUM					9
#define CHUNK_CLONE						10
#define CHUNK_BREED						11
#define CHUNK_SUSPEND_WRITE				12
#define CHUNK_NOTIFY_NEW_REPLICA		13
#define CHUNK_INCUBATION_DONE			14
#define CHUNK_START_INCUBATION			15
#define CHUNK_UNDELETE					16
#define CHUNK_SERVER_TERMINATE			17
#define CHUNK_SERVER_PING				18
#define CHUNK_RENAME					19
#define CHUNK_UPDATA					20
#define CHUNK_WRITE_REPLICATE3			21
#define CHUNK_WRITE3					22
#define CHUNK_READ3						23
#define CHUNK_WRITE_REPLICATE2			24
#define CHUNK_SYNC_DATA					25
#define CHUNK_GET_INFO					26
#define CHUNK_GET_JOURNAL				27
#define CHUNK_SERVER_RESTART			28
#define CHUNK_WRITE_REPLICATE4			29
#define CHUNK_WRITE4					30
#define CHUNK_READ4						31

#define CHUNK_WRITE_EC_DATA				32
#define CHUNK_UPDATE_EC_PARITY			33
#define CHUNK_WRITE_ECGROUP_DATA		34
#define CHUNK_WRITE_EC_ON_ERROR			35
#define CHUNK_FIX_CREATE				36
#define CHUNK_WRITE_EC_PARITY			37
#define CHUNK_WRITE_EC					38
#define CHUNK_GET_EC_VERSION			39
#define CHUNK_NOTIFY_NEW_EC				40
#define CHECK_EC_PARITY_RIGHT			41
#define CHUNK_FIX_CREATE2				42
#define CHECK_EC_PARITY_RIGHT2			43
#define CHUNK_CLEAR_EC_RECORD			44
#define CHUNK_CHECK_SUSPEND				45

#define CHUNK_FLUSH_JOURNAL				46
#define CHUNK_GET_BIG_JOURNAL_META		47

#define CHUNK_WRITE_EC_DATA2			48
#define CHUNK_WRITE_DATA_TO_PARITY		49
#define CHUNK_FLUSH_EC_JOURNAL			50
#define CHUNK_GET_EC_JOURNAL_META		51

// for write parity first
#define CHUNK_WRITE_ECGROUP_DATA2		52
#define CHUNK_WRITE_EC2					53
#define CHUNK_WRITE_EC_PARITY_CHECK		54
#define CLOSE_CHUNK_FD					55




#define MGR_REQ_CHUNK_CREATE			202
#define MGR_REQ_CHUNK_MOVE				208
#define MGR_REQ_SERVER_ERROR			302
#define MGR_REQ_SERVER_UP				303
#define MGR_REQ_SERVER_ERROR2			305
#define MGR_REQ_SERVER_ERROR3			307
#define MGR_REQ_CLIENT_FAULT			602
#define MGR_REQ_VOLUME_CREATE			101
#define MGR_REQ_VOLUME_OPEN				102
#define MGR_REQ_VOLUME_SETFMT			110
#define MGR_REQ_VOLUME_OPENC			111
#define MGR_REQ_VOLUME_CLOSE			103
#define MGR_REQ_VOLUME_RESIZE			104
#define MGR_REQ_SNAPSHOT_ADD			115
#define MGR_REQ_SNAPSHOT_UPDATE			116
#define MGR_REQ_SNAPSHOT_DELETE			117
#define MGR_REQ_SNAPSHOT_GET			118
#define MGR_REQ_VOLUME_SETACTIVE		119
#define MGR_REQ_VOLUME_OPEN2			121
#define MGR_REQ_VOLUME_CLOSE2			122
#define MGR_REQ_VOLUME_BACKUP_ADD		123
#define MGR_REQ_VOLUME_BACKUP_UPDATE	124
#define MGR_REQ_VOLUME_BACKUP_DELETE	125
#define MGR_REQ_VOLUME_BACKUP_GET		126
#define MGR_REQ_VOLUME_OPEN3			133 // only get volume info




struct CSEP		// Chunk Server Endpoint
{
	uint32_t ip;
	uint16_t port;
};

// the maximum number of replications
#define MAX_REPLICATIONS 7

/**** start of section: request to master ****/
struct MgrReqChunkLocate
{
	struct ProtocolHeader header;
	uint32_t volumeid;
	uint64_t volume_size;
	uint16_t cs_cnt;	 // number of replicas
	uint32_t chunk_size; // byte
	uint32_t chunk_index; // UINT_MAX represents not specified
};

struct MgrRespChunkLocate
{
	struct ProtocolHeader header;
	int16_t retcode;
	union 
	{
		struct
		{
			uint16_t cs_cnt;
			struct CSEP csids[0];			
		};
		struct Data msg;
	};
};

struct MgrReqServerUp
{
	struct ProtocolHeader header;
	struct CSEP csid;
	int16_t upcode; // use for debug
};

struct MgrRespServerUp
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqChunkError
{
	struct ProtocolHeader header;
	struct CSEP csid;
	uint16_t operation;
	int16_t connection_error_code;
	int16_t operation_error_code;
};

struct MgrRespChunkError
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, 
	struct Data msg;
};

struct MgrReqChunkError2
{
	struct ProtocolHeader header;
	struct CSEP csid;
	struct ChunkID id;
	uint16_t operation;
	int16_t connection_error_code;
	int16_t operation_error_code;
};

struct MgrRespChunkError2
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, 
	struct Data msg;
};

struct MgrReqChunkError3
{
	struct ProtocolHeader header;
	struct CSEP csid;
	struct ChunkID id;
	uint16_t operation;
	int16_t connection_error_code;
	int16_t operation_error_code;
	uint16_t k;
	uint16_t n;
	uint32_t chunk_size;
	uint32_t stripe_size_shift;
};

struct MgrRespChunkError3
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0,
	struct Data msg;
};

struct MgrReqChunkMove
{
	struct ProtocolHeader header;
	bool byid;
	uint32_t volumeid;
	uint32_t index;
	uint32_t from_ip;
	uint16_t from_port;
	uint32_t to_ip;
	uint16_t to_port;
};

struct MgrRespChunkMove
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqClientFault
{
	struct ProtocolHeader header;
	uint32_t volumeid;
	struct Data clientid;
};

struct MgrRespClientFault
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqVolumeCreate
{
	struct ProtocolHeader header;
	uint64_t size;
	struct Data name;
	struct Data desc;
	struct {
		uint32_t chunk_size;
		uint16_t repnum;
		bool create_chunks;
		bool prealloc;
	} data;
};

struct MgrRespVolumeCreate
{
	struct ProtocolHeader header;
	int16_t retcode;
	uint32_t volumeid;
	struct Data msg;
};

struct MgrReqVolumeOpen
{
	struct ProtocolHeader header;
	uint32_t volumeid;
	bool readonly;
	struct Data clientid;
};

struct MgrRespVolumeOpen
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0 for success, <0 for error
	union
	{
		struct Data jvolume;	// volume meta-data, encoded in json
		struct Data msg;
	};
};

struct MgrReqVolumeOpenName
{
	struct ProtocolHeader header;
	bool byid;
	uint16_t name;
	char _[0];// real name
	bool readonly;
	struct Data clientid;
};

typedef struct MgrReqVolumeOpen2
{
	struct ProtocolHeader header;
	int major_version;
	int minor_version;
	int patch_version;
	uint32_t volumeid;
	bool readonly;
	struct Data clientid;
} MgrReqVolumeOpen2;

typedef struct MgrRespVolumeOpen MgrRespVolumeOpen2;

struct MgrReqVolumeClose
{
	struct ProtocolHeader header;
	bool force;
	bool byid;
	uint32_t volumeid;
	struct Data clientid;
};

struct MgrRespVolumeClose
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0 for success, <0 for error
	struct Data msg;
};

typedef struct MgrReqVolumeClose MgrReqVolumeClose2;
typedef struct MgrRespVolumeClose MgrRespVolumeClose2;

struct MgrReqVolumeResize
{
	struct ProtocolHeader header;
	uint32_t volumeid;
	uint64_t new_size;		// in byte
	bool preallocation;
};

struct MgrRespVolumeResize
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0 for success, <0 for error
	struct Data msg;
};

struct MgrReqVolumeSetfmt
{
	struct ProtocolHeader header;
	bool byid;
	uint32_t volumeid;
	uint16_t new_fmt;
	uint64_t virtual_size;
};

struct MgrRespVolumeSetfmt
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqVolumeSetActive
{
	struct ProtocolHeader header;
	bool byid;
	uint32_t volumeid;
};

struct MgrRespVolumeSetActive
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqSnapshotAdd
{
	struct ProtocolHeader header;
	struct Data msg; // json of struct Snapshot
};

struct MgrRespSnapshotAdd
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

typedef struct MgrReqSnapshotAdd MgrReqSnapshotUpdate;
typedef struct MgrRespSnapshotAdd MgrRespSnapshotUpdate;

struct MgrReqSnapshotDelete
{
	struct ProtocolHeader header;
	uint32_t volume_id;
	uint32_t id;
};

struct MgrRespSnapshotDelete
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqSnapshotGet
{
	struct ProtocolHeader header;
	uint32_t volume_id;
};

struct MgrRespSnapshotGet
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg; // json of some struct Snapshot
};

struct MgrReqBackupAdd
{
	struct ProtocolHeader header;
	struct Data msg; // json of struct Backup
};

struct MgrRespBackupAdd
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

typedef struct MgrReqBackupAdd MgrReqBackupUpdate;
typedef struct MgrRespBackupAdd MgrRespBackupUpdate;

struct MgrReqBackupDelete
{
	struct ProtocolHeader header;
	uint32_t volume_id;
	bool force;
	struct Data name;
};

struct MgrRespBackupDelete
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct MgrReqBackupGet
{
	struct ProtocolHeader header;
	uint32_t volume_id;
};

struct MgrRespBackupGet
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg; // json of some struct Backup
};



/**** end of section: request to master ****/


#define CHUNK_CREATE_PREALLOCATION		1
#define CHUNK_CREATE_INCUBATION			2
#define CHUNK_CREATE_WITH_CHECKSUM		4
#define CHUNK_CREATE_EC_CHUNK			8


struct Request_ChunkCreate
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t size;			// in byte
	uint16_t flags;			// CHUNK_CREATE_PREALLOCATION | CHUNK_CREATE_INCUBATION | CHUNK_CREATE_WITH_CHECKSUM | CHUNK_CREATE_EC_CHUNK
};

struct Response_ChunkCreate
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_INVALID_ARGUMENTS, ERROR_CHUNK_EXISTS, ERROR_DISK_IO, ERROR_INTERNAL
	struct Data msg;
};

struct Request_ChunkCloseFd
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkCloseFd
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkList
{
	struct ProtocolHeader header;
	uint32_t volumeid;
};

struct Response_ChunkList
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0
	union
	{
		struct Data msg;
		struct
		{
			uint32_t count;
			struct ChunkID ids[0];
		} chunks;
	};
};

struct Request_ChunkRead
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t offset, size;
};

struct Response_ChunkRead
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, 
	union
	{
		struct Data data;
		struct Data msg;
	};
};

struct Request_ChunkRead4
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t offset, size;
	uint64_t success_version;
};

struct Response_ChunkRead4
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION,
	union
	{
		struct Data data;
		struct Data msg;
	};
};

struct SyncDataExtraInfo
{
	bool sync_data_from_version0;
	bool sync_data_from_range;
	uint32_t range_start;
	uint32_t range_length;
};

struct Request_ChunkSyncData
{
	struct ProtocolHeader header;
	struct ChunkID id;
	struct CSEP src_chunk;
	struct SyncDataExtraInfo sync_extra_info;
};

struct Response_ChunkSyncData
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION,
	union
	{
		struct Data data;
		struct Data msg;
	};
};

struct Request_ChunkGetInfo
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkGetInfo
{
	struct ProtocolHeader header;
	int16_t retcode;
	uint32_t chunk_data_size;
	union
	{
		struct Data data;
		struct Data msg;
	};
	// struct ChunkExtra4K info;
};

#define MAX_FOLLOWING_SERVERS (MAX_REPLICATIONS-1)

#define GET_JOURNAL_NO_SUSPEND (1<<0)
struct Request_ChunkGetJournal
{
	struct ProtocolHeader header;
	struct ChunkID id;
	struct CSEP breed_to;
	uint64_t since_version;
	uint32_t flag;
};

#define JOURNAL_DATA_MAGIC (0x12abcdef) // normal data
#define JOURNAL_END_MAGIC (0x13abcdef) // end transmission
struct Journal
{
	uint32_t magic;
	union{
		struct{
			uint32_t offset;
			uint32_t length;
		};
		uint64_t version;
	};
	char data[0];
};

struct Response_ChunkGetJournal
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
	// +
	// some struct SyncData
};

struct Request_ChunkRead3
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t offset, size;
};

struct Response_ChunkRead3
{
	struct ProtocolHeader header;
	int16_t retcode;
	union
	{
		struct Data data;
		struct Data msg; // len(data) = data.length + crc32_nb * sizeof(uint32_t)
	};
};

struct Request_ChunkWrite
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint64_t version;		// current version before write
	uint32_t offset;
	struct Data data;
};

struct Response_ChunkWrite
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO, ERROR_RETRY
	struct Data msg;
};

struct Request_ChunkWrite3
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t flag;
	uint64_t version;
	uint32_t offset;
	struct Data data; // data.length + crc32_nb * sizeof(uint32_t) = len(data)
};

struct Response_ChunkWrite3
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};


struct Request_ChunkWriteReplicate
{
	struct ProtocolHeader header;
	struct CSEP servers[MAX_FOLLOWING_SERVERS];	// 1+6 == 7 == 1+2+4
	struct ChunkID id;
	uint32_t offset;
	struct Data data;
};

struct Response_ChunkWriteReplicate
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO, ERROR_RETRY
							// 1~6, the number of non-primary write failures
							// if the primary fail, the OP will fail
	bool need_to_update_replicas;
	struct Data msg;		// first error msg
};

// for ret version, and error replicate
struct Request_ChunkWriteReplicate2
{
	struct ProtocolHeader header;
	struct CSEP servers[MAX_FOLLOWING_SERVERS];	// 1+6 == 7 == 1+2+4
	struct ChunkID id;
	uint32_t offset;
	struct Data data;
};

struct Response_ChunkWriteReplicate2
{
	struct ProtocolHeader header;
	int16_t retcode;
	bool need_to_update_replicas;
	int8_t ret_values[MAX_FOLLOWING_SERVERS]; // 0 is success
	uint64_t current_version;
	struct Data msg;
};

struct Request_ChunkWriteReplicate3
{
	struct ProtocolHeader header;
	struct CSEP servers[MAX_FOLLOWING_SERVERS];	// 1+6 == 7 == 1+2+4
	struct ChunkID id;
	uint32_t offset;
	uint32_t flag;
	struct Data data; // data.length + ckinfo.crc32_nb * sizeof(uint32_t) = data length
};

// now, same as Response_ChunkWriteReplicate
struct Response_ChunkWriteReplicate3
{
	struct ProtocolHeader header;
	int16_t retcode;
	bool need_to_update_replicas;
	struct Data msg;
};

#define FLAG_NO_CHECK_NEW (1<<0)
#define CHECK_NEW_FLAG(flag) (!(flag & FLAG_NO_CHECK_NEW))
struct Request_ChunkWriteReplicate4
{
	struct ProtocolHeader header;
	struct CSEP servers[MAX_FOLLOWING_SERVERS];	// 1+6 == 7 == 1+2+4
	struct ChunkID id;
	uint32_t offset;
	uint32_t flag;
	uint64_t data_version;
	union{
		uint64_t padding;
		time_t client_time;
	};
	struct Data data; // data.length + ckinfo.crc32_nb * sizeof(uint32_t) = data length
};

struct Response_ChunkWriteReplicate4
{
	struct ProtocolHeader header;
	int16_t retcode;
	bool need_to_update_replicas;
	int8_t ret_values[MAX_FOLLOWING_SERVERS]; // 0 is success
	uint64_t chunk_version;
	struct Data msg;
};

struct Request_ChunkWrite4
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint64_t version;		// current version before write
	uint32_t flag;
	uint32_t offset;
	union{
		uint64_t padding;
		time_t client_time;
	};
	struct Data data;
};

struct Response_ChunkWrite4
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO, ERROR_RETRY
	struct Data msg;
};

#define EC_MAX_K (16)
#define EC_MAX_N (4)
struct ECDataWriteinfo
{
	struct ChunkID id;
	uint32_t offset;
	uint32_t ec_opsn;
	uint8_t ith;
	uint8_t k;		// k is the # of source data blocks, 
	uint8_t n;		// n is the # of EC parity (coded) blocks
	uint8_t n_chunks_involved;			// # of source chunks involves in current write operation
	struct CSEP ec_servers[EC_MAX_N];	// chunk servers that serve EC parity (coded) chunks
	// time_t ec_servers_updatetime[EC_MAX_N];
	uint64_t version_from_client;
	uint8_t wait_suspend;
	//uint32_t ec_start_chunk_index;
	// ec location |------|------|------|------|******|######|
	// in this case, k = 4, n =2
	// case 1        |---|    data is less than a stripe, n_chunks_involved is 1
	// case 2      |------|   data is equel to 1 stripe, client sends data to the chunk, offset is chunk offset, n_chunks_involved is 1
	// case 3      |------|------| data is equal to 2 stripes, client sends data to both, n_chunks_involved is 2
	// case 4      |------|------|-------| data is equal to 3 stripes, client sends data to all them, n_chunks_involved is 3
	// case 5      |---|  |---|  not useful, n_chunks_involved is 2
};

struct Request_ChunkWriteECData
{
	struct ProtocolHeader header;
	struct ECDataWriteinfo info;
	struct Data data;
};

struct WriteECDataRet
{
	union
	{
		struct
		{
			uint16_t success_mask; // bit 0 success, 1 failed
			char padding[2];
		};
		uint32_t i;
	};
};

struct Response_ChunkWriteECData
{
	struct ProtocolHeader header;
	union{
		int32_t retcode;
		struct WriteECDataRet ret;
	};
	union{
		char writen_to_disk_nb;
		char success_mask; // for ERROR_MORE_REPLICATE_FAILED
	};
	char new_replicate;
	struct Data msg;
};

#define CONFIRM_WRITE_CODE (999)
struct Request_ChunkWriteEC
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint64_t version;
	uint32_t offset;
	struct Data data;
};

struct Response_ChunkWriteEC
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkWriteECParity
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint64_t versions[EC_MAX_K]; // old versions check
	uint8_t inc_versions[EC_MAX_K];
	uint8_t k;
	uint32_t offset;
	struct Data data;
};

struct Response_ChunkWriteECParity
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkGetECVersion
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint32_t nb_to_get;
};

struct Response_ChunkGetECVersion
{
	struct ProtocolHeader header;
	int16_t retcode;
	uint64_t versions[EC_MAX_K];
	struct Data msg;
};

struct Request_ChunkNotifyNewECChunk
{
	struct ProtocolHeader header;
	struct ChunkID id;
	int m;
	struct CSEP new_addr;
	struct ChunkID new_id;
};

struct Response_ChunkNotifyNewECChunk
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkClearEcRecord
{
	struct ProtocolHeader header;
	struct ChunkID id;
	int ith;
};

struct Response_ChunkClearEcRecord
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct ECParityUpdateInfo
{
	uint32_t volumeid;
	uint32_t index;
	uint32_t offset;
	uint32_t ec_opsn;
	uint8_t k;
	union{
	uint8_t n_chunks_involved;			// # of source chunks involves in current write operation
	uint8_t n; // # for chunk_write_data_to_parity, n_chunks_involved not need and n is needed
	};
	uint32_t from_chunk_index_off;
	uint64_t from_version;
};

struct Request_ChunkUpdateECParity
{
	struct ProtocolHeader header;
	struct ECParityUpdateInfo info;
	struct Data data;
};

struct Response_ChunkUpdateECParity
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct ECGroupDataWriteInfo
{
	struct ChunkID id;
	uint32_t offset;	// offset of the stripe group within each chunk
	uint32_t start;		// start position of the write within the stripe group
	uint8_t k;			// k is the # of source data blocks, 
	uint8_t n;			// n is the # of EC parity (coded) blocks
	uint8_t ec_stripe_size_shift; // 2^ec_stripe_size k byte
	uint8_t padding;
	struct CSEP data_ec_servers[EC_MAX_K+EC_MAX_N]; // data head, ec tail, in sequence
	uint64_t versions_from_client[EC_MAX_K];
	uint8_t wait_suspend;

	//data           |---------------------------|
	// ---offset-----|
	//  g-offset-----|

	//data                    |<-  len   >|
	//     ---------offset----|
	// ---group off--|
	// in this case, chunkserver will read the other data from the other chunk

	// ec location   |------|------|------|------|******|######|
};
#define GET_EC_STRIP_SIZE(ec_stripe_size_shift) (1024*(1<<ec_stripe_size_shift))

struct Request_ChunkWriteECGroupData
{
	struct ProtocolHeader header;
	struct ECGroupDataWriteInfo info;
	struct Data data;
};

struct GECWriteRet
{
	union
	{
		struct
		{
			unsigned int success_mask:24; // bit 0 success, 1 failed
			unsigned int padding:6;
			unsigned int failed:1; // if set, this write is not success. success_mask will ret failed ones
			unsigned int symbol:1;
		};
		uint32_t i;
	};
};

struct Response_ChunkWriteECGroupData
{
	struct ProtocolHeader header;
	union
	{
		int32_t retcode;
		struct GECWriteRet ret;
	};
	uint32_t new_replicate;
	struct Data msg;
};

struct WriteECOnErrInfo
{
	struct ChunkID id;
	uint32_t offset;	// offset of the stripe group within each chunk
	uint8_t k;
	uint8_t n;
	uint8_t stripe_start;
	uint8_t stripe_end;
	struct CSEP data_ec_servers[EC_MAX_K+EC_MAX_N]; // data head, ec tail, in sequence, ip 0 means broken chunk
	uint64_t versions_from_client[EC_MAX_K];
	uint8_t wait_suspend;
};

struct Request_ChunkWriteECOnErr
{
	struct ProtocolHeader header;
	struct WriteECOnErrInfo info;
	struct Data data;
};

struct NewChunk
{
	struct CSEP cs;
	struct ChunkID id;
};

struct Response_ChunkWriteECOnErr
{
	struct ProtocolHeader header;
	union
	{
		int32_t retcode;
		uint32_t success_mask; // bit 0 success, 1 failed
	};
	struct CSEP data_ec_servers[EC_MAX_K+EC_MAX_N];
	uint32_t new_replicate;
	struct Data msg; // struct NewChunkRet, some new chunk
};

struct Request_ChunkCheckParityRight
{
	struct ProtocolHeader header;
	uint8_t k;
	uint8_t n;
	struct ChunkID start_id;
	uint32_t chunk_size;
	struct CSEP chunks[];
};

struct Response_ChunkCheckParityRight
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct ECFixCreateInfo
{
	struct ChunkID id;
	uint8_t k;
	uint8_t n;
	uint8_t __;
	uint8_t force_fix; // this will ignore version
	uint32_t chunk_size;
	struct CSEP data_ec_servers[0];
};

struct Request_ChunkECFixCreate
{
	struct ProtocolHeader header;
	struct ECFixCreateInfo info;
	struct CSEP data_ec_servers[0]; // data ahead, ec tail, in sequence
};

struct Response_ChunkECFixCreate
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

typedef struct Request_ChunkECFixCreate Request_ChunkECFixCreate2;
typedef struct Response_ChunkECFixCreate Response_ChunkECFixCreate2;


typedef struct Request_ChunkWriteECData Request_ChunkWriteECData2;
typedef struct Response_ChunkWriteECData Response_ChunkWriteECData2;

struct ReWriteD0Record
{
	uint64_t dn_meta_offset;
	uint64_t dn_data_offset;
	uint64_t d0_meta_offset;
	uint64_t d0_data_offset;
	uint32_t hash_of_extra_datas; // dn_meta_offset + dn_data_offset + d0_meta_offset + d0_data_offset + len. crc
};

struct Request_ChunkWriteDataToParity
{
	struct ProtocolHeader header;
	struct ECParityUpdateInfo info;
	bool is_d0_data;
	struct ReWriteD0Record d0_record;
	struct Data data;
};

struct Response_ChunkWriteDataToParity
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct ReWriteD0Record d0_record;
	struct Data msg;
};

struct Request_ChunkFlushECJournal
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkFlushECJournal
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkGetEcJournal
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkGetEcJournal
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct {
		uint64_t length;
	} msg;
};

struct Request_ChunkCreateWriteReplicate
{
	struct ProtocolHeader header;
	struct CSEP servers[MAX_FOLLOWING_SERVERS];
	struct ChunkID id;
	uint32_t offset;
	uint32_t size;			// chunk size in byte
	uint16_t flags;			// CHUNK_CREATE_PREALLOCATION | CHUNK_CREATE_INCUBATION | CHUNK_CREATE_WITH_CHECKSUM
	struct Data data;
};

struct Response_ChunkCreateWriteReplicate
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_INVALID_ARGUMENTS, ERROR_CHUNK_EXISTS, ERROR_DISK_IO, ERROR_INTERNAL
							// 1~6, the number of non-primary write failures
							// if the primary fail, the OP will fail
	bool need_to_update_replicas;
	struct Data msg;		// first error msg
};

struct Request_ChunkGetVersion
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkGetVersion
{
	struct ProtocolHeader header;
	uint64_t version;	
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION
	struct Data msg;
};

struct Request_ChunkFlush
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkFlush
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO
	struct Data msg;
};

struct Request_ChunkDelete
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkDelete
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_DISK_IO
	struct Data msg;
};

struct Request_ChunkUndelete
{
	struct ProtocolHeader header;
	struct ChunkID id;		// if (id.index == -1) { undelete all chunks of id.volumeid; }
};

struct Response_ChunkUndelete
{
	struct ProtocolHeader header;
	int16_t retcode;		// # of undeleted chunks (>0), ERROR_CHUNK_NOT_FOUND, ERROR_DISK_IO
	struct Data msg;
};

struct Request_ChunkChecksum
{
	struct ProtocolHeader header;
	struct ChunkID id;
	char algorithm;			// 0 for sha1 , 1 for crc32
};

struct Response_ChunkChecksum
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO, -1
	union
	{
		struct Data hash;
		struct Data msg;
	};
};

struct Request_ChunkClone	// not implemented
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_ChunkClone
{
	struct ProtocolHeader header;
	int16_t retcode;		// ERROR_NOT_IMPLEMENTED
	struct Data msg;
};

struct Request_ChunkBreed
{
	struct ProtocolHeader header;
	struct ChunkID id;
	struct CSEP to;
	uint64_t since_version;	// 0 for a full-data breed， -1 for auto-detected incremental incubation
};

struct Response_ChunkBreed
{
	struct ProtocolHeader header;
	int16_t retcode;		// returns 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION
	struct Data msg;
};

struct Request_ChunkSuspendWrite
{
	struct ProtocolHeader header;
	struct ChunkID id;
	bool to_suspend;
};

struct Response_ChunkSuspendWrite
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0
	struct Data msg;
};

struct Request_NotifyNewReplica
{
	struct ProtocolHeader header;
	struct ChunkID id;
	struct CSEP server;
};

struct Response_NotifyNewReplica
{
	struct ProtocolHeader header;
	int16_t retcode;		// 0
	struct Data msg;
};

struct Request_NotifyIncubationDone
{
	struct ProtocolHeader header;
	struct ChunkID id;
	uint64_t version;		// final version, -1 indicates a failed incubation
};

struct Response_NotifyIncubationDone
{
	struct ProtocolHeader header;
	int16_t retcode;		// returns 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO
	struct Data msg;
};

struct Request_StartIncubation
{
	struct ProtocolHeader header;
	struct ChunkID id;
};

struct Response_StartIncubation
{
	struct ProtocolHeader header;
	uint64_t current_version;
	int16_t retcode;		// returns 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION, ERROR_DISK_IO
	struct Data msg;
};

struct Request_ChunkServerTerminate
{
	struct ProtocolHeader header;
	int code;				// should be 0, other values are reserved for future use
};

struct Response_ChunkServerTerminate
{
	struct ProtocolHeader header;
	int16_t retcode;		// returns 0 (should be always sucessful)
	struct Data msg;
};

struct Request_ChunkServerPing
{
	struct ProtocolHeader header;
	int code;
};

struct Response_ChunkServerPing
{
	struct ProtocolHeader header;
	int16_t retcode;
	union 
	{
		struct Data code;		// sprintfs request.code into response.code
		struct Data msg;
	};
};

typedef struct Request_ChunkServerPing2
{
	struct ProtocolHeader header;
	struct ChunkID id;
} Request_ChunkServerPing2_t;

typedef struct Response_ChunkServerPing Response_ChunkServerPing2_t;

struct Request_ChunkServerRestart
{
	struct ProtocolHeader header;
	int code;
};

struct Response_ChunkServerRestart
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkRename
{
	struct ProtocolHeader header;
	struct ChunkID id, id1;
};

struct Response_ChunkRename
{
	struct ProtocolHeader header;
	int16_t retcode;		// returns 0, ERROR_CHUNK_NOT_FOUND, ERROR_INTERNAL, ERROR_VERSION
	struct Data msg;
};

struct Request_ChunkUpdate
{
	struct ProtocolHeader header;
	uint32_t data;
};

struct Response_ChunkUpdate
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

#define DELETE_AFTER_FLUSH (1<<0)
struct Request_ChunkFlushJournal
{
	struct ProtocolHeader header;
	uint32_t flag;
};

struct Response_ChunkFlushJournal
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct Data msg;
};

struct Request_ChunkGetBigJournalMeta
{
	struct ProtocolHeader header;
	uint32_t flag;
};

struct Response_ChunkGetBigJournalMeta
{
	struct ProtocolHeader header;
	int16_t retcode;
	struct {
		uint64_t length;
	} msg;
};

#define ERROR_CHUNK_NOT_FOUND		-10
#define ERROR_CHUNK_EXISTS			-11
#define ERROR_DISK_IO				-12
#define ERROR_INTERNAL				-13
#define ERROR_VERSION				-14
#define ERROR_NOT_IMPLEMENTED		-15
#define ERROR_INVALID_ARGUMENTS		-16
#define ERROR_NOT_ENOUGH_REPLIAS	-17
#define ERROR_NETWORK_CHECKSUM		-18 // checksum not right
#define ERROR_DISK_CHECKSUM			-19
#define ERROR_CANT_CONNECT_SRC		-20
#define ERROR_MULTY_BREED			-21
#define ERROR_NOT_EC_CHUNK			-22
#define ERROR_EC_CHUNK_MISS			-23
#define ERROR_SUSPENDED				-24
#define ERROR_NEW_EC_CHUNK			-25
#define ERROR_DATA					-26 // ec journal d0 miss
#define ERROR_MORE_REPLICATE_FAILED	-27 // ec too many replicate failed
#define ERROR_HASH_FOR_D0			-28
#define ERROR_LOCKED				-30
#define ERROR_CANT_SUSPEND			-31
#define ERROR_REPLICATE_SAMEHOST	-32
#define ERROR_EC_SAMEHOST			-33
#define ERROR_EC_WRITE_ABORT		-34
#define ERROR_NOP_DEBUG				-999


#define THRESHOLD 10000
#define MK_CONNECTION_ERROR(x) 		((x < 0) ? (x - THRESHOLD) : 0)
#define CONNECTION_ERROR(x)			((x < -THRESHOLD) ? (x + THRESHOLD) : 0)
#define MK_OPERATION_ERROR(x)		x
#define OPERATION_ERROR(x)			((x >= -THRESHOLD) ? x : 0)
// #define OPSN_ERROR MK_CONNECTION_ERROR(0x3456)
#define OPSN_ERROR MK_CONNECTION_ERROR(-1)


#pragma pack(pop)
#endif

